package org.dromara.web.service.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.aizuda.snailjob.common.core.model.Result;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.dromara.bean.domain.HisMember;
import org.dromara.bean.domain.bo.HisMemberBo;
import org.dromara.bean.domain.vo.HisMemberVo;
import org.dromara.bean.mapper.HisMemberMapper;
import org.dromara.bean.service.IHisMemberService;
import org.dromara.bean.util.HttpUtil;
import org.dromara.common.core.domain.model.XcxLoginBody;
import org.dromara.common.core.domain.model.XcxLoginUser;
import org.dromara.common.core.enums.UserStatus;
import org.dromara.common.core.service.DictService;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

/**
 * 小程序认证策略
 *
 * @author Michelle.Chung
 */
@Slf4j
@Service("xcx" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class XcxAuthStrategy implements IAuthStrategy {

    private final SysLoginService loginService;
    @Autowired
    private DictService dictService;

    @Resource
    private IHisMemberService hisMemberService;
    @Resource
    private HisMemberMapper hisMemberMapper;

    @Override
    public LoginVo login(String body, SysClientVo client) {
        XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class);
        ValidatorUtils.validate(loginBody);
        // xcxCode 为 小程序调用 wx.login 授权后获取
        String xcxCode = loginBody.getXcxCode();


        String appid = dictService.getDictValue("wx_config", "appId");
        String appSrcret = dictService.getDictValue("wx_config", "appSecret");

        // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
        JSONObject context = getSessionKeyOrOpenId(xcxCode,appid, appSrcret );
//        log.warn("患者微信小程序{},openid:{} ",context);
        if (context.containsKey("errcode")) {
            log.warn("微信小程序openid: " + context);
            new RuntimeException("微信小程序openid获取失败");
        }

        String openid = context.getString("openid");
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        HisMemberVo user = loadUserByOpenid(openid,loginBody.getMobile());

        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        XcxLoginUser loginUser = new XcxLoginUser();
//        loginUser.setTenantId(user.getTenantId());
        loginUser.setUserId(user.getId());
        loginUser.setUsername(user.getName());
        loginUser.setNickname(user.getNickName());
//        loginUser.setUserType(user.getUserType());
        loginUser.setClientKey(client.getClientKey());
        loginUser.setDeviceType(client.getDeviceType());
        loginUser.setUserType(user.getUserType());
        loginUser.setOpenid(openid);
        loginUser.setTenantId(loginBody.getTenantId());
        SaLoginModel model = new SaLoginModel();
        model.setDevice(client.getDeviceType());
        // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
        // 例如: 后台用户30分钟过期 app用户1天过期
        model.setTimeout(client.getTimeout());
        model.setActiveTimeout(client.getActiveTimeout());
        model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
        // 生成token
        LoginHelper.xcxLogin(loginUser, model);

        LoginVo loginVo = new LoginVo();
        loginVo.setAccessToken(StpUtil.getTokenValue());
        loginVo.setExpireIn(StpUtil.getTokenTimeout());
        loginVo.setClientId(client.getClientId());
        loginVo.setOpenid(openid);
        return loginVo;
    }

    private HisMemberVo loadUserByOpenid(String openid,String mobile) {
        // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
        HisMemberVo hisMemberVo = hisMemberService.selectUserByOpenid(openid);

        if (ObjectUtil.isNull(hisMemberVo)) {
            HisMember hisMember = new HisMember();
            hisMember.setOpenId(openid);
            hisMember.setMobile(mobile);
            hisMember.setName("微信用户");
            hisMember.setNickName("微信用户");
            hisMember.setUserType("huanzhe");
            hisMemberMapper.insert(hisMember);

            hisMemberVo = hisMemberService.selectUserByOpenid(openid);
        }

        return hisMemberVo;
    }


    /**
     * 这是通过公众号获取openid 统一方法
     *
     * @param appId
     * @param appSecret
     * @param code
     * @return
     */

    public JSONObject getOpenIdByWechatAPP(String appId, String appSecret, String code) {
        String openidUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?";
        StringBuilder url = new StringBuilder();
        url.append(openidUrl);
        url.append("appid=");
        url.append(appId.trim());
        url.append("&secret=");
        url.append(appSecret.trim());
        url.append("&code=");
        url.append(code);
        url.append("&grant_type=authorization_code");
        RestTemplate restTemplate = new RestTemplate();
        String json = restTemplate.getForObject(url.toString(), String.class);
        JSONObject jsonObject = JSONObject.parseObject(json);
        log.warn("accessTokenWechatUserInfo------------------------" + JSONObject.toJSONString(jsonObject));
        return jsonObject;
    }


    /**
     * 这是通过小程序获取openid 统一方法
     *
     * @param appId
     * @param appSecret
     * @param code
     * @return
     */
    public static JSONObject getSessionKeyOrOpenId(String code, String appId, String appSecret) {
        //微信端登录code
        String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";
        Map<String, String> requestUrlParam = new HashMap<String, String>();
        requestUrlParam.put("appid", appId);//小程序appId
        requestUrlParam.put("secret", appSecret);
        requestUrlParam.put("js_code", code);//小程序端返回的code
        requestUrlParam.put("grant_type", "authorization_code");//默认参数
        log.warn("请求地址：【{}】，请求参数：【{}】", requestUrl, JSONObject.toJSONString(requestUrlParam));
        //发送post请求读取调用微信接口获取openid用户唯一标识
        String response = HttpUtil.doGet(requestUrl, requestUrlParam);
        log.warn("回文：【{}】", response);
        JSONObject jsonObject = JSON.parseObject(response);
        return jsonObject;
    }

}
